#!/bin/bash
###############################################################################
#       脚本名称: utils_number.sh
#       功能描述: 数字处理工具类功能函数，提供纯粹的数字处理功能
#       作者: 林再来
#       日期: 2025-10-20
#       版本: 1.0
#       功能:
#           1、数字格式化和转换
#           2、数字验证和校验
#           3、数学运算和计算
#           4、数字比较和排序
#           5、随机数生成
#           6、进制转换
#           7、数字统计和分析
#       依赖(插件/命令):
#           1、bash
#           2、bc (可选，用于高精度计算)
#           3、awk(可选，用于复杂计算)
###############################################################################

# 防止重复加载
if [[ -n "${utils_number_sh_loaded:-}" ]]; then
    return 0
fi
readonly utils_number_sh_loaded=1

# 注意：不使用严格模式，避免影响交互式 shell

# 获取脚本目录和项目根目录（如果尚未定义）
if [[ -z "${script_dir:-}" ]]; then
    script_dir="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
    readonly script_dir
fi

if [[ -z "${project_root:-}" ]]; then
    project_root="$(cd "${script_dir}/../.." && pwd)"
    readonly project_root
fi

###############################################################################
# 全局常量
###############################################################################

# 数字类型常量
readonly UTILS_NUMBER_TYPE_INTEGER="integer"
readonly UTILS_NUMBER_TYPE_FLOAT="float"
readonly UTILS_NUMBER_TYPE_POSITIVE="positive"
readonly UTILS_NUMBER_TYPE_NEGATIVE="negative"
readonly UTILS_NUMBER_TYPE_ZERO="zero"

# 精度常量
readonly UTILS_NUMBER_PRECISION_DEFAULT=2
readonly UTILS_NUMBER_PRECISION_HIGH=10

# 进制常量
readonly UTILS_NUMBER_BASE_BINARY=2
readonly UTILS_NUMBER_BASE_OCTAL=8
readonly UTILS_NUMBER_BASE_DECIMAL=10
readonly UTILS_NUMBER_BASE_HEXADECIMAL=16

###############################################################################
# 数字验证函数
###############################################################################

# 函数: 检查是否为数字
# 参数: $1 - 输入值
# 返回: 0-是数字, 1-不是数字
# 说明: 检查输入值是否为有效数字
function utils_number_is_number() {
    local input="$1"
    
    if [[ -z "$input" ]]; then
        return 1
    fi
    
    # 检查是否为整数或浮点数
    [[ "$input" =~ ^-?[0-9]+(\.[0-9]+)?$ ]]
}

# 函数: 检查是否为整数
# 参数: $1 - 输入值
# 返回: 0-是整数, 1-不是整数
# 说明: 检查输入值是否为整数
function utils_number_is_integer() {
    local input="$1"
    
    if [[ -z "$input" ]]; then
        return 1
    fi
    
    [[ "$input" =~ ^-?[0-9]+$ ]]
}

# 函数: 检查是否为浮点数
# 参数: $1 - 输入值
# 返回: 0-是浮点数, 1-不是浮点数
# 说明: 检查输入值是否为浮点数
function utils_number_is_float() {
    local input="$1"
    
    if [[ -z "$input" ]]; then
        return 1
    fi
    
    [[ "$input" =~ ^-?[0-9]+\.[0-9]+$ ]]
}

# 函数: 检查是否为正数
# 参数: $1 - 输入值
# 返回: 0-是正数, 1-不是正数
# 说明: 检查输入值是否为正数
function utils_number_is_positive() {
    local input="$1"
    
    if ! utils_number_is_number "$input"; then
        return 1
    fi
    
    # 使用bc进行精确比较
    if command -v bc >/dev/null 2>&1; then
        [[ $(echo "$input > 0" | bc) -eq 1 ]]
    else
        # 简单字符串比较（适用于整数）
        [[ "$input" =~ ^[0-9]+(\.[0-9]+)?$ ]] && [[ "$input" != "0" ]]
    fi
}

# 函数: 检查是否为负数
# 参数: $1 - 输入值
# 返回: 0-是负数, 1-不是负数
# 说明: 检查输入值是否为负数
function utils_number_is_negative() {
    local input="$1"
    
    if ! utils_number_is_number "$input"; then
        return 1
    fi
    
    # 使用bc进行精确比较
    if command -v bc >/dev/null 2>&1; then
        [[ $(echo "$input < 0" | bc) -eq 1 ]]
    else
        # 简单字符串比较
        [[ "$input" =~ ^-[0-9]+(\.[0-9]+)?$ ]]
    fi
}

# 函数: 检查是否为零
# 参数: $1 - 输入值
# 返回: 0-是零, 1-不是零
# 说明: 检查输入值是否为零
function utils_number_is_zero() {
    local input="$1"
    
    if ! utils_number_is_number "$input"; then
        return 1
    fi
    
    # 使用bc进行精确比较
    if command -v bc >/dev/null 2>&1; then
        [[ $(echo "$input == 0" | bc) -eq 1 ]]
    else
        # 简单字符串比较
        [[ "$input" == "0" ]] || [[ "$input" == "0.0" ]]
    fi
}

# 函数: 检查数字是否在范围内
# 参数: $1 - 输入值, $2 - 最小值, $3 - 最大值
# 返回: 0-在范围内, 1-不在范围内
# 说明: 检查数字是否在指定范围内
function utils_number_in_range() {
    local input="$1"
    local min="$2"
    local max="$3"
    
    if ! utils_number_is_number "$input"; then
        return 1
    fi
    
    # 使用bc进行精确比较
    if command -v bc >/dev/null 2>&1; then
        local ge_min=$(echo "$input >= $min" | bc)
        local le_max=$(echo "$input <= $max" | bc)
        [[ $ge_min -eq 1 ]] && [[ $le_max -eq 1 ]]
    else
        # 使用awk进行浮点数比较
        if command -v awk >/dev/null 2>&1; then
            awk "BEGIN {exit !($input >= $min && $input <= $max)}"
        else
            # 简单比较（仅适用于整数）
            if utils_number_is_integer "$input" && utils_number_is_integer "$min" && utils_number_is_integer "$max"; then
                [[ $input -ge $min ]] && [[ $input -le $max ]]
            else
                # 对于浮点数，使用printf进行字符串比较（有限精度）
                local input_str=$(printf "%.10f" "$input" 2>/dev/null || echo "$input")
                local min_str=$(printf "%.10f" "$min" 2>/dev/null || echo "$min")
                local max_str=$(printf "%.10f" "$max" 2>/dev/null || echo "$max")
                [[ "$input_str" = "$min_str" ]] || [[ "$input_str" > "$min_str" ]] && [[ "$input_str" = "$max_str" ]] || [[ "$input_str" < "$max_str" ]]
            fi
        fi
    fi
}

###############################################################################
# 数字格式化函数
###############################################################################

# 函数: 格式化数字（添加千分位分隔符）
# 参数: $1 - 输入数字, $2 - 分隔符（可选，默认为逗号）
# 返回: 格式化后的数字字符串
# 说明: 为数字添加千分位分隔符
function utils_number_format_thousands() {
    local input="$1"
    local separator="${2:-,}"
    
    if ! utils_number_is_number "$input"; then
        echo "$input"
        return 1
    fi
    
    # 处理负号
    local sign=""
    if [[ "$input" =~ ^- ]]; then
        sign="-"
        input="${input#-}"
    fi
    
    # 分离整数和小数部分
    local integer_part="${input%%.*}"
    local decimal_part="${input#*.}"
    
    # 为整数部分添加千分位分隔符
    local formatted_integer=""
    local len=${#integer_part}
    for ((i=0; i<len; i++)); do
        if [[ $((i % 3)) -eq 0 ]] && [[ $i -gt 0 ]]; then
            formatted_integer="${separator}${formatted_integer}"
        fi
        formatted_integer="${integer_part:$((len-i-1)):1}${formatted_integer}"
    done
    
    # 组合结果
    if [[ "$decimal_part" != "$input" ]]; then
        echo "${sign}${formatted_integer}.${decimal_part}"
    else
        echo "${sign}${formatted_integer}"
    fi
}

# 函数: 格式化浮点数精度
# 参数: $1 - 输入数字, $2 - 小数位数（可选，默认为2）
# 返回: 格式化后的数字字符串
# 说明: 控制浮点数的小数位数
function utils_number_format_precision() {
    local input="$1"
    local precision="${2:-$UTILS_NUMBER_PRECISION_DEFAULT}"
    
    if ! utils_number_is_number "$input"; then
        echo "$input"
        return 1
    fi
    
    # 使用printf格式化
    printf "%.${precision}f" "$input"
}

# 函数: 转换为百分比
# 参数: $1 - 输入数字, $2 - 小数位数（可选，默认为2）
# 返回: 百分比字符串
# 说明: 将数字转换为百分比格式
function utils_number_to_percentage() {
    local input="$1"
    local precision="${2:-$UTILS_NUMBER_PRECISION_DEFAULT}"
    
    if ! utils_number_is_number "$input"; then
        echo "$input"
        return 1
    fi
    
    # 计算百分比
    local percentage
    if command -v bc >/dev/null 2>&1; then
        percentage=$(echo "scale=$precision; $input * 100" | bc)
    else
        # 简单计算（精度有限）
        percentage=$(awk "BEGIN {printf \"%.${precision}f\", $input * 100}")
    fi
    
    echo "${percentage}%"
}

# 函数: 转换为科学计数法
# 参数: $1 - 输入数字, $2 - 小数位数（可选，默认为2）
# 返回: 科学计数法字符串
# 说明: 将数字转换为科学计数法格式
function utils_number_to_scientific() {
    local input="$1"
    local precision="${2:-$UTILS_NUMBER_PRECISION_DEFAULT}"
    
    if ! utils_number_is_number "$input"; then
        echo "$input"
        return 1
    fi
    
    # 使用printf转换为科学计数法
    printf "%.${precision}e" "$input"
}

###############################################################################
# 数学运算函数
###############################################################################

# 函数: 加法运算
# 参数: $1 - 第一个数, $2 - 第二个数
# 返回: 运算结果
# 说明: 执行加法运算
function utils_number_add() {
    local num1="$1"
    local num2="$2"
    
    if ! utils_number_is_number "$num1" || ! utils_number_is_number "$num2"; then
        echo "错误: 参数不是有效数字" >&2
        return 1
    fi
    
    # 使用bc进行精确计算
    if command -v bc >/dev/null 2>&1; then
        echo "$num1 + $num2" | bc
    else
        # 简单计算（精度有限）
        awk "BEGIN {print $num1 + $num2}"
    fi
}

# 函数: 减法运算
# 参数: $1 - 被减数, $2 - 减数
# 返回: 运算结果
# 说明: 执行减法运算
function utils_number_subtract() {
    local num1="$1"
    local num2="$2"
    
    if ! utils_number_is_number "$num1" || ! utils_number_is_number "$num2"; then
        echo "错误: 参数不是有效数字" >&2
        return 1
    fi
    
    # 使用bc进行精确计算
    if command -v bc >/dev/null 2>&1; then
        echo "$num1 - $num2" | bc
    else
        # 简单计算（精度有限）
        awk "BEGIN {print $num1 - $num2}"
    fi
}

# 函数: 乘法运算
# 参数: $1 - 第一个数, $2 - 第二个数
# 返回: 运算结果
# 说明: 执行乘法运算
function utils_number_multiply() {
    local num1="$1"
    local num2="$2"
    
    if ! utils_number_is_number "$num1" || ! utils_number_is_number "$num2"; then
        echo "错误: 参数不是有效数字" >&2
        return 1
    fi
    
    # 使用bc进行精确计算
    if command -v bc >/dev/null 2>&1; then
        echo "$num1 * $num2" | bc
    else
        # 简单计算（精度有限）
        awk "BEGIN {print $num1 * $num2}"
    fi
}

# 函数: 除法运算
# 参数: $1 - 被除数, $2 - 除数, $3 - 小数位数（可选，默认为10）
# 返回: 运算结果
# 说明: 执行除法运算
function utils_number_divide() {
    local num1="$1"
    local num2="$2"
    local precision="${3:-$UTILS_NUMBER_PRECISION_HIGH}"
    
    if ! utils_number_is_number "$num1" || ! utils_number_is_number "$num2"; then
        echo "错误: 参数不是有效数字" >&2
        return 1
    fi
    
    if utils_number_is_zero "$num2"; then
        echo "错误: 除数不能为零" >&2
        return 1
    fi
    
    # 使用bc进行精确计算
    if command -v bc >/dev/null 2>&1; then
        echo "scale=$precision; $num1 / $num2" | bc
    else
        # 简单计算（精度有限）
        awk "BEGIN {printf \"%.${precision}f\", $num1 / $num2}"
    fi
}

# 函数: 幂运算
# 参数: $1 - 底数, $2 - 指数
# 返回: 运算结果
# 说明: 执行幂运算
function utils_number_power() {
    local base="$1"
    local exponent="$2"
    
    if ! utils_number_is_number "$base" || ! utils_number_is_number "$exponent"; then
        echo "错误: 参数不是有效数字" >&2
        return 1
    fi
    
    # 使用bc进行精确计算
    if command -v bc >/dev/null 2>&1; then
        echo "$base ^ $exponent" | bc
    else
        # 简单计算（精度有限）
        awk "BEGIN {print $base ^ $exponent}"
    fi
}

# 函数: 平方根
# 参数: $1 - 输入数字, $2 - 小数位数（可选，默认为10）
# 返回: 平方根
# 说明: 计算数字的平方根
function utils_number_sqrt() {
    local input="$1"
    local precision="${2:-$UTILS_NUMBER_PRECISION_HIGH}"
    
    if ! utils_number_is_number "$input"; then
        echo "错误: 参数不是有效数字" >&2
        return 1
    fi
    
    if utils_number_is_negative "$input"; then
        echo "错误: 负数不能计算平方根" >&2
        return 1
    fi
    
    # 使用bc进行精确计算
    if command -v bc >/dev/null 2>&1; then
        echo "scale=$precision; sqrt($input)" | bc
    else
        # 简单计算（精度有限）
        awk "BEGIN {printf \"%.${precision}f\", sqrt($input)}"
    fi
}

###############################################################################
# 数字比较函数
###############################################################################

# 函数: 比较两个数字
# 参数: $1 - 第一个数字, $2 - 第二个数字
# 返回: 0-相等, 1-第一个大, 2-第二个大
# 说明: 比较两个数字的大小
function utils_number_compare() {
    local num1="$1"
    local num2="$2"
    
    if ! utils_number_is_number "$num1" || ! utils_number_is_number "$num2"; then
        echo "错误: 参数不是有效数字" >&2
        return 3
    fi
    
    # 使用bc进行精确比较
    if command -v bc >/dev/null 2>&1; then
        local result=$(echo "$num1 < $num2" | bc)
        if [[ $result -eq 1 ]]; then
            return 2  # num2 > num1
        fi
        
        result=$(echo "$num1 > $num2" | bc)
        if [[ $result -eq 1 ]]; then
            return 1  # num1 > num2
        fi
        
        return 0  # num1 == num2
    else
        # 使用awk进行浮点数比较
        if command -v awk >/dev/null 2>&1; then
            local result=$(awk "BEGIN {if ($num1 < $num2) print 2; else if ($num1 > $num2) print 1; else print 0}")
            return $result
        else
            # 简单比较（仅适用于整数）
            if utils_number_is_integer "$num1" && utils_number_is_integer "$num2"; then
                if [[ $num1 -lt $num2 ]]; then
                    return 2
                elif [[ $num1 -gt $num2 ]]; then
                    return 1
                else
                    return 0
                fi
            else
                # 对于浮点数，使用printf进行字符串比较（有限精度）
                local num1_str=$(printf "%.10f" "$num1" 2>/dev/null || echo "$num1")
                local num2_str=$(printf "%.10f" "$num2" 2>/dev/null || echo "$num2")
                if [[ "$num1_str" < "$num2_str" ]]; then
                    return 2
                elif [[ "$num1_str" > "$num2_str" ]]; then
                    return 1
                else
                    return 0
                fi
            fi
        fi
    fi
}

# 函数: 获取最大值
# 参数: $1... - 数字列表
# 返回: 最大值
# 说明: 从数字列表中获取最大值
function utils_number_max() {
    local max="$1"
    shift
    
    for num in "$@"; do
        if ! utils_number_is_number "$num"; then
            echo "错误: 参数不是有效数字: $num" >&2
            return 1
        fi
        
        utils_number_compare "$num" "$max"
        case $? in
            1) max="$num" ;;  # num > max
        esac
    done
    
    echo "$max"
}

# 函数: 获取最小值
# 参数: $1... - 数字列表
# 返回: 最小值
# 说明: 从数字列表中获取最小值
function utils_number_min() {
    local min="$1"
    shift
    
    for num in "$@"; do
        if ! utils_number_is_number "$num"; then
            echo "错误: 参数不是有效数字: $num" >&2
            return 1
        fi
        
        utils_number_compare "$num" "$min"
        case $? in
            2) min="$num" ;;  # num < min
        esac
    done
    
    echo "$min"
}

###############################################################################
# 随机数生成函数
###############################################################################

# 函数: 生成随机整数
# 参数: $1 - 最小值, $2 - 最大值
# 返回: 随机整数
# 说明: 在指定范围内生成随机整数
function utils_number_random_int() {
    local min="$1"
    local max="$2"
    
    if ! utils_number_is_integer "$min" || ! utils_number_is_integer "$max"; then
        echo "错误: 参数必须是整数" >&2
        return 1
    fi
    
    if [[ $min -gt $max ]]; then
        echo "错误: 最小值不能大于最大值" >&2
        return 1
    fi
    
    # 使用$RANDOM生成随机数
    local range=$((max - min + 1))
    echo $((RANDOM % range + min))
}

# 函数: 生成随机浮点数
# 参数: $1 - 最小值, $2 - 最大值, $3 - 小数位数（可选，默认为2）
# 返回: 随机浮点数
# 说明: 在指定范围内生成随机浮点数
function utils_number_random_float() {
    local min="$1"
    local max="$2"
    local precision="${3:-$UTILS_NUMBER_PRECISION_DEFAULT}"
    
    if ! utils_number_is_number "$min" || ! utils_number_is_number "$max"; then
        echo "错误: 参数必须是数字" >&2
        return 1
    fi
    
    if utils_number_compare "$min" "$max" && [[ $? -eq 1 ]]; then
        echo "错误: 最小值不能大于最大值" >&2
        return 1
    fi
    
    # 生成随机浮点数
    local range
    if command -v bc >/dev/null 2>&1; then
        range=$(echo "$max - $min" | bc)
        local random_ratio=$(echo "scale=$precision; $RANDOM / 32767" | bc)
        local result=$(echo "scale=$precision; $min + $range * $random_ratio" | bc)
        echo "$result"
    else
        # 简单实现（精度有限）
        local range=$(awk "BEGIN {print $max - $min}")
        local random_ratio=$(awk "BEGIN {print $RANDOM / 32767}")
        awk "BEGIN {printf \"%.${precision}f\", $min + $range * $random_ratio}"
    fi
}

###############################################################################
# 进制转换函数
###############################################################################

# 函数: 十进制转二进制
# 参数: $1 - 十进制数字
# 返回: 二进制字符串
# 说明: 将十进制数字转换为二进制
function utils_number_dec_to_bin() {
    local decimal="$1"
    
    if ! utils_number_is_integer "$decimal"; then
        echo "错误: 参数必须是整数" >&2
        return 1
    fi
    
    # 处理负数
    local sign=""
    if [[ $decimal -lt 0 ]]; then
        sign="-"
        decimal=$((decimal * -1))
    fi
    
    # 转换为二进制
    local binary=""
    while [[ $decimal -gt 0 ]]; do
        binary="$((decimal % 2))$binary"
        decimal=$((decimal / 2))
    done
    
    # 处理零的情况
    if [[ -z "$binary" ]]; then
        binary="0"
    fi
    
    echo "${sign}${binary}"
}

# 函数: 二进制转十进制
# 参数: $1 - 二进制字符串
# 返回: 十进制数字
# 说明: 将二进制字符串转换为十进制数字
function utils_number_bin_to_dec() {
    local binary="$1"
    
    # 验证二进制格式
    if [[ ! "$binary" =~ ^-?[01]+$ ]]; then
        echo "错误: 参数不是有效的二进制格式" >&2
        return 1
    fi
    
    # 处理负数
    local sign=""
    if [[ "$binary" =~ ^- ]]; then
        sign="-"
        binary="${binary#-}"
    fi
    
    # 转换为十进制
    local decimal=0
    local len=${#binary}
    for ((i=0; i<len; i++)); do
        local bit="${binary:$((len-i-1)):1}"
        decimal=$((decimal + bit * (2 ** i)))
    done
    
    echo "${sign}${decimal}"
}

# 函数: 十进制转十六进制
# 参数: $1 - 十进制数字
# 返回: 十六进制字符串
# 说明: 将十进制数字转换为十六进制
function utils_number_dec_to_hex() {
    local decimal="$1"
    
    if ! utils_number_is_integer "$decimal"; then
        echo "错误: 参数必须是整数" >&2
        return 1
    fi
    
    # 使用printf转换
    printf "%x" "$decimal"
}

# 函数: 十六进制转十进制
# 参数: $1 - 十六进制字符串
# 返回: 十进制数字
# 说明: 将十六进制字符串转换为十进制数字
function utils_number_hex_to_dec() {
    local hex="$1"
    
    # 验证十六进制格式
    if [[ ! "$hex" =~ ^-?[0-9a-fA-F]+$ ]]; then
        echo "错误: 参数不是有效的十六进制格式" >&2
        return 1
    fi
    
    # 使用printf转换
    printf "%d" "0x$hex"
}

###############################################################################
# 统计函数
###############################################################################

# 函数: 计算平均值
# 参数: $1... - 数字列表
# 返回: 平均值
# 说明: 计算数字列表的平均值
function utils_number_average() {
    local sum=0
    local count=0
    
    for num in "$@"; do
        if ! utils_number_is_number "$num"; then
            echo "错误: 参数不是有效数字: $num" >&2
            return 1
        fi
        
        sum=$(utils_number_add "$sum" "$num")
        count=$((count + 1))
    done
    
    if [[ $count -eq 0 ]]; then
        echo "错误: 没有有效数字" >&2
        return 1
    fi
    
    utils_number_divide "$sum" "$count"
}

# 函数: 计算总和
# 参数: $1... - 数字列表
# 返回: 总和
# 说明: 计算数字列表的总和
function utils_number_sum() {
    local sum=0
    
    for num in "$@"; do
        if ! utils_number_is_number "$num"; then
            echo "错误: 参数不是有效数字: $num" >&2
            return 1
        fi
        
        sum=$(utils_number_add "$sum" "$num")
    done
    
    echo "$sum"
}

# 函数: 计算绝对值
# 参数: $1 - 输入数字
# 返回: 绝对值
# 说明: 计算数字的绝对值
function utils_number_abs() {
    local input="$1"
    
    if ! utils_number_is_number "$input"; then
        echo "错误: 参数不是有效数字" >&2
        return 1
    fi
    
    if utils_number_is_negative "$input"; then
        echo "${input#-}"
    else
        echo "$input"
    fi
}

# 函数: 四舍五入
# 参数: $1 - 输入数字, $2 - 小数位数（可选，默认为0）
# 返回: 四舍五入后的数字
# 说明: 对数字进行四舍五入
function utils_number_round() {
    local input="$1"
    local precision="${2:-0}"
    
    if ! utils_number_is_number "$input"; then
        echo "错误: 参数不是有效数字" >&2
        return 1
    fi
    
    # 使用printf进行四舍五入
    printf "%.${precision}f" "$input"
}
